package com.seven.rsa;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import static javax.crypto.Cipher.*;

public class RSADemo {

    public static void main(String[] args) throws Exception{
        //加密明文
        String input = "硅谷";

        //创建密钥对
        //KeyPairGenerator:密钥对生成器对象
        String algorithm="RSA";

        //生成密钥对并保存在本地文件中
        generateKeyToFile(algorithm,"a.pub","a.pri");

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        //生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //生成私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //生成公钥
        PublicKey publicKey = keyPair.getPublic();
       /* //获取私钥字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        //获取公钥字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        //使用base64进行编码，转换成字符串
        String privateEncodeString = Base64.encode(privateKeyEncoded);
        String publicEncodeString = Base64.encode(publicKeyEncoded);*/

        //读取私钥字符窜
        String privateKeyString = getPrivateKeyString("a.pri");
        System.out.println("私钥字符窜="+privateKeyString);
        //读取私钥对象
        PrivateKey privateKeyObj = getPrivateKey("a.pri", algorithm);
        System.out.println("私钥对象="+privateKeyObj);


        //读取公钥字符窜
        String publicKeyString = getPublicKeyString("a.pub");
        System.out.println("公钥字符窜="+publicKeyString);
        //读取公钥对象
        PublicKey publicKeyObj = getPublicKey("a.pub", algorithm);
        System.out.println("公钥对象="+publicKeyObj);


        //加密后的密文
        String EncryptCodeString = encryptRSA(input, algorithm, privateKey);
        //解密后的明文
        String DecryptCodeString = decryptRSA(publicKey, algorithm, EncryptCodeString);

        System.out.println("加密后的密文="+EncryptCodeString.length());
        System.out.println("解密后的明文="+DecryptCodeString);

    }



    /**
     * 读取公钥
     * @param PubPath：公钥地址
     * @param algorithm：算法
     * @return 公钥对象
     * @throws Exception：抛异常
     */
    public static PublicKey getPublicKey(String PubPath, String algorithm) throws Exception{
        String PublicKeyString = FileUtils.readFileToString(new File(PubPath), Charset.defaultCharset());
        //创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //创建公钥key的规则
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(PublicKeyString));
        //返回公钥对象
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 读取公钥字符窜
     * @param PubPath：公钥地址
     * @return 公钥字符窜
     */
    private static String getPublicKeyString(String PubPath) throws Exception{
        String publicKeyString = FileUtils.readFileToString(new File(PubPath), Charset.defaultCharset());
        return publicKeyString;
    }

    /**
     * 读取私钥字符窜
     * @param PriPath：私钥地址
     * @return 私钥字符串
     */
    private static String getPrivateKeyString(String PriPath) throws Exception {
        String privateKeyString = FileUtils.readFileToString(new File(PriPath), Charset.defaultCharset());
        return privateKeyString;
    }

    /**
     * 读取私钥
     * @param PriPath：私钥地址
     * @param algorithm：算法
     * @return 私钥key对象
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String PriPath, String algorithm) throws Exception {
        String privateKeyString = FileUtils.readFileToString(new File(PriPath), Charset.defaultCharset());
        //创建key的工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //创建私钥key的规则
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        //返回私钥对象
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * RSA私钥解密方法
     * @param privateKey：私钥
     * @param algorithm：加密算法
     * @param EncryptCode：密文
     * @return 明文
     * @throws Exception 抛出异常
     */
    private static String decryptRSAByprivateKey(PrivateKey privateKey,String algorithm,String EncryptCode) throws Exception {
        //创建加密对象
        Cipher cipher = getInstance(algorithm);
        //公钥解密
        cipher.init(DECRYPT_MODE,privateKey);
        //使用公钥解密
        byte[] DencryptBytes = cipher.doFinal(Base64.decode(EncryptCode));
        //base64进行编码
        String DecryptCode = new String(DencryptBytes);
        return DecryptCode;
    }


    /**
     * RSA公钥解密方法
     * @param publicKey：公钥
     * @param algorithm：加密算法
     * @param EncryptCode：密文
     * @return 明文
     * @throws Exception 抛出异常
     */
    private static String decryptRSA(PublicKey publicKey,String algorithm,String EncryptCode) throws Exception {
        //创建加密对象
        Cipher cipher = getInstance(algorithm);
        //公钥解密
        cipher.init(DECRYPT_MODE,publicKey);
        //使用公钥解密
        byte[] DencryptBytes = cipher.doFinal(Base64.decode(EncryptCode));
        //base64进行编码
        String DecryptCode = new String(DencryptBytes);
        return DecryptCode;
    }

    /**
     * RSA私钥加密方法
     * @param input：明文
     * @param algorithm：加密方式
     * @param privateKey：私钥
     * @return  ：密文
     * @throws Exception：抛出异常
     */
    private static String encryptRSA(String input, String algorithm,Key privateKey) throws Exception{
        //创建加密对象
        Cipher cipher = getInstance(algorithm);
        /**
         * 对加密进行初始化
         * 参数一：加密模式
         * 参数二：使用公钥还是私钥进行加密
         * 示例：使用私钥进行加密
         */
        cipher.init(ENCRYPT_MODE,privateKey);
        //cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        //使用私钥进行加密
        byte[] EncryptBytes = cipher.doFinal(input.getBytes());
        String EncryptCode = Base64.encode(EncryptBytes);
        return EncryptCode;
    }

    /**
     * 保存密钥对
     * @param algorithm：加密类型
     * @param pubPath：公钥保存地址
     * @param priPath：私钥保存地址
     */
    private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception{

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        //生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //生成私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //生成公钥
        PublicKey publicKey = keyPair.getPublic();
        //获取私钥字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        //获取公钥字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        //使用base64进行编码，转换成字符串
        String privateEncodeString = Base64.encode(privateKeyEncoded);
        String publicEncodeString = Base64.encode(publicKeyEncoded);
        //把公钥和私钥保存到根目录
        FileUtils.writeStringToFile(new File(pubPath),publicEncodeString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath),privateEncodeString, Charset.forName("UTF-8"));
    }
}
